package gui

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"

	cosclient "github.com/liyixin123/my-cos-project/internal/cosclient"
)

// App 主应用结构
type App struct {
	app           fyne.App
	window        fyne.Window
	configManager *ConfigManager
	client        cosclient.Client

	// 管理器组件
	uiComponents   *UIComponents
	sortManager    *SortManager
	fileOperations *FileOperations

	// 数据
	files           []*FileInfo
	allFiles        []*FileInfo
	currentDir      string
	directories     []string
	selectedFileIdx int
	searchKeyword   string

	// 排序相关 (保持向后兼容)
	sortBy        string // "name", "size", "time"
	sortAscending bool

	// CLI相关
	useCLIUpload  bool
	cliBinaryPath string
}

// NewApp 创建新应用
func NewApp() *App {
	fyneApp := app.NewWithID("com.liyixin.cos-gui")
	fyneApp.SetIcon(theme.StorageIcon())

	window := fyneApp.NewWindow("COS 文件管理器")
	window.Resize(fyne.NewSize(1000, 700))
	window.SetMaster()

	cfgManager := NewConfigManager()

	guiApp := &App{
		app:             fyneApp,
		window:          window,
		configManager:   cfgManager,
		directories:     []string{"全部", "images", "documents", "audio", "videos", "archives", "code", "others"},
		currentDir:      "",
		selectedFileIdx: -1,
		sortBy:          "time",
		sortAscending:   false,
	}

	// 初始化管理器
	guiApp.uiComponents = NewUIComponents(guiApp)
	guiApp.sortManager = NewSortManager()
	guiApp.sortManager.SetSortOrder(guiApp.sortBy, guiApp.sortAscending)
	guiApp.fileOperations = NewFileOperations(guiApp)

	return guiApp
}

// Run 运行应用
func (a *App) Run() {
	// 加载配置
	if err := a.configManager.Load(); err != nil {
		log.Printf("加载配置失败: %v", err)
	}

	if cfg := a.configManager.Config(); cfg != nil {
		a.useCLIUpload = cfg.UseCLIUpload
	}

	// 创建界面
	a.createUI()

	// 设置拖拽事件处理
	a.window.SetOnDropped(a.onFileDropped)

	// 尝试初始化客户端
	a.initClient()

	a.window.ShowAndRun()
}

// initClient 初始化云存储客户端
func (a *App) initClient() {
	if !a.configManager.Config().IsValid() {
		a.uiComponents.GetConnectionInfo().SetText("配置不完整")
		a.uiComponents.GetConnectionInfo().Importance = widget.DangerImportance
		return
	}

	client, err := cosclient.NewClient(a.configManager.Config())
	if err != nil {
		a.uiComponents.GetConnectionInfo().SetText("连接失败")
		a.uiComponents.GetConnectionInfo().Importance = widget.DangerImportance
		a.showError("初始化客户端失败", err)
		return
	}

	a.client = client
	a.testConnection()
}

// testConnection 测试连接
func (a *App) testConnection() {
	if a.client == nil {
		a.uiComponents.GetConnectionInfo().SetText("未配置")
		a.uiComponents.GetConnectionInfo().Importance = widget.DangerImportance
		return
	}

	go func() {
		if err := a.client.TestConnection(); err != nil {
			fyne.Do(func() {
				a.uiComponents.GetConnectionInfo().SetText("连接失败: " + err.Error())
				a.uiComponents.GetConnectionInfo().Importance = widget.DangerImportance
			})
		} else {
			fyne.Do(func() {
				a.uiComponents.GetConnectionInfo().SetText("已连接")
				a.uiComponents.GetConnectionInfo().Importance = widget.SuccessImportance
				a.refreshFileList()
			})
		}
	}()
}

// refreshFileList 刷新文件列表
func (a *App) refreshFileList() {
	if a.client == nil {
		return
	}

	a.setStatus("正在加载文件列表...")

	go func() {
		files, err := a.client.ListFiles(a.currentDir)
		if err != nil {
			// 更新状态消息
			fyne.Do(func() {
				a.setStatus("加载文件列表失败: " + err.Error())
			})
			return
		}

		// 更新数据和UI
		fyne.Do(func() {
			a.allFiles = files
			a.selectedFileIdx = -1

			filteredCount := a.applyFilters()

			// 强制刷新列表组件
			if fileList := a.uiComponents.GetFileList(); fileList != nil {
				fileList.UnselectAll()
				fileList.Refresh()
				fileList.ScrollToTop()
			}

			a.updateStatusAfterFilter(filteredCount)
		})
	}()
}

// createUI 创建用户界面
func (a *App) createUI() {
	// 创建配置区域
	configArea := a.uiComponents.CreateConfigArea()

	// 创建主内容区域
	mainContent := a.createMainContent()

	// 创建底部状态栏
	statusBar := a.uiComponents.CreateStatusBar()

	// 主布局
	content := container.NewBorder(
		configArea,  // 顶部
		statusBar,   // 底部
		nil,         // 左侧
		nil,         // 右侧
		mainContent, // 中心
	)

	a.window.SetContent(content)
}

// createMainContent 创建主内容区域
func (a *App) createMainContent() *container.Split {
	// 左侧目录列表
	directoryList := a.uiComponents.CreateDirectoryList()

	// 右侧文件列表和操作按钮
	rightPanel := a.uiComponents.CreateFilePanel()

	// 分割面板
	split := container.NewHSplit(
		container.NewBorder(
			widget.NewCard("目录", "", nil).Content,
			nil, nil, nil,
			directoryList,
		),
		rightPanel,
	)
	split.Offset = 0.25

	return split
}

// showUploadDialog 显示上传对话框
func (a *App) showUploadDialog() {
	a.fileOperations.ShowUploadDialog()
}

// downloadSelectedFile 下载选中的文件
func (a *App) downloadSelectedFile() {
	a.fileOperations.DownloadSelectedFile()
}

// deleteSelectedFile 删除选中的文件
func (a *App) deleteSelectedFile() {
	a.fileOperations.DeleteSelectedFile()
}

// copyLinkToClipboard 复制文件链接到剪贴板
func (a *App) copyLinkToClipboard() {
	a.fileOperations.CopyLinkToClipboard()
}

// copyMarkdownLinkToClipboard 复制Markdown格式链接到剪贴板
func (a *App) copyMarkdownLinkToClipboard() {
	a.fileOperations.CopyMarkdownLinkToClipboard()
}

// setSearchKeyword 设置搜索关键字并更新列表
func (a *App) setSearchKeyword(keyword string) {
	trimmed := strings.TrimSpace(keyword)
	if a.searchKeyword == trimmed {
		return
	}

	a.searchKeyword = trimmed
	a.selectedFileIdx = -1

	filteredCount := a.applyFilters()

	if fileList := a.uiComponents.GetFileList(); fileList != nil {
		fileList.UnselectAll()
		fileList.Refresh()
		fileList.ScrollToTop()
	}

	a.updateStatusAfterFilter(filteredCount)
}

// setStatus 设置状态
func (a *App) setStatus(status string) {
	if statusLabel := a.uiComponents.GetStatusLabel(); statusLabel != nil {
		statusLabel.SetText(status)
	}
}

// showInfo 显示信息
func (a *App) showInfo(message string) {
	dialog.NewInformation("信息", message, a.window).Show()
}

// showError 显示错误
func (a *App) showError(title string, err error) {
	dialog.NewError(err, a.window).Show()
}

// setSortBy 设置排序方式 (保持向后兼容)
func (a *App) setSortBy(sortBy string) {
	a.sortManager.SetSortBy(sortBy)
	a.sortBy = a.sortManager.GetSortBy()
	a.sortAscending = a.sortManager.IsAscending()

	a.sortFiles()
	if fileList := a.uiComponents.GetFileList(); fileList != nil {
		fileList.Refresh()
	}

	// 更新排序头部显示
	a.uiComponents.UpdateSortHeaders()
}

// sortFiles 对文件列表进行排序 (保持向后兼容)
func (a *App) sortFiles() {
	a.sortManager.SortFiles(a.files)
}

// applyFilters 根据搜索关键字过滤文件
func (a *App) applyFilters() int {
	if len(a.allFiles) == 0 {
		a.files = make([]*FileInfo, 0)
		return 0
	}

	keyword := strings.ToLower(strings.TrimSpace(a.searchKeyword))
	filtered := make([]*FileInfo, 0, len(a.allFiles))

	for _, file := range a.allFiles {
		if keyword == "" || strings.Contains(strings.ToLower(file.Name), keyword) {
			filtered = append(filtered, file)
		}
	}

	a.files = filtered
	a.sortFiles()

	return len(filtered)
}

// updateStatusAfterFilter 根据过滤结果更新状态栏
func (a *App) updateStatusAfterFilter(filteredCount int) {
	total := len(a.allFiles)
	if strings.TrimSpace(a.searchKeyword) != "" {
		a.setStatus(fmt.Sprintf("找到 %d 个匹配结果 (共 %d 个文件)", filteredCount, total))
		return
	}

	if a.currentDir == "" {
		a.setStatus(fmt.Sprintf("共 %d 个文件", total))
	} else {
		a.setStatus(fmt.Sprintf("%s 目录: %d 个文件", a.currentDir, total))
	}
}

// formatFileSize 格式化文件大小
func formatFileSize(bytes int64) string {
	const unit = 1024
	if bytes < unit {
		return fmt.Sprintf("%d B", bytes)
	}

	div, exp := int64(unit), 0
	for n := bytes / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}

	return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}

// onFileDropped 处理文件拖拽事件
func (a *App) onFileDropped(position fyne.Position, uris []fyne.URI) {
	if len(uris) == 0 {
		return
	}

	// 只处理文件，不处理目录
	var filesToUpload []string
	for _, uri := range uris {
		if uri.Scheme() == "file" {
			// 检查是否为文件（而非目录）
			localPath := strings.TrimSpace(uri.Path())
			if localPath == "" {
				continue
			}

			normalizedPath, err := a.normalizeDroppedPath(localPath)
			if err != nil {
				log.Printf("拖拽路径转换失败: %q: %v", localPath, err)
				a.showError("路径转换失败", fmt.Errorf("无法转换路径 %s: %w", localPath, err))
				continue
			}

			filesToUpload = append(filesToUpload, normalizedPath)
		}
	}

	if len(filesToUpload) > 0 {
		// 显示确认对话框，无论是使用CLI还是GUI上传都需要确认
		message := fmt.Sprintf("确定要上传这 %d 个文件吗？", len(filesToUpload))
		if len(filesToUpload) == 1 {
			message = fmt.Sprintf("确定要上传文件 '%s' 吗？", filepath.Base(filesToUpload[0]))
		}

		dialog.NewConfirm("确认上传", message, func(confirmed bool) {
			if confirmed {
				// 根据配置决定使用哪种上传方式
				if a.useCLIUpload {
					// 使用CLI方式上传所有文件
					for _, filePath := range filesToUpload {
						a.fileOperations.UploadFileWithCLI(filePath)
					}
				} else {
					// 使用GUI方式上传所有文件
					for _, filePath := range filesToUpload {
						a.fileOperations.UploadFile(filePath)
					}
				}
			}
		}, a.window).Show()
	}
}

func (a *App) normalizeDroppedPath(path string) (string, error) {
	trimmed := strings.TrimSpace(path)
	if trimmed == "" {
		return "", fmt.Errorf("路径为空")
	}

	if !isWSLEnvironment() {
		return trimmed, nil
	}

	if !isWindowsStylePath(trimmed) {
		return trimmed, nil
	}

	converted, err := convertWindowsPathToWSL(trimmed)
	if err != nil {
		return "", err
	}

	return converted, nil
}

func isWSLEnvironment() bool {
	if runtime.GOOS != "linux" {
		return false
	}

	if os.Getenv("WSL_DISTRO_NAME") != "" || os.Getenv("WSL_INTEROP") != "" {
		return true
	}

	if _, err := os.Stat("/proc/sys/fs/binfmt_misc/WSLInterop"); err == nil {
		return true
	}

	return false
}

func isWindowsStylePath(path string) bool {
	if strings.HasPrefix(path, "/mnt/") {
		return false
	}

	candidate := strings.TrimPrefix(path, "/")
	if len(candidate) > 1 && candidate[1] == ':' {
		drive := candidate[0]
		if (drive >= 'A' && drive <= 'Z') || (drive >= 'a' && drive <= 'z') {
			return true
		}
	}

	if len(path) > 1 && path[1] == ':' {
		drive := path[0]
		return (drive >= 'A' && drive <= 'Z') || (drive >= 'a' && drive <= 'z')
	}

	return false
}

func convertWindowsPathToWSL(path string) (string, error) {
	candidate := strings.TrimPrefix(path, "file://")
	candidate = strings.TrimPrefix(candidate, "/")

	if len(candidate) < 2 || candidate[1] != ':' {
		return "", fmt.Errorf("不是合法的 Windows 路径: %s", path)
	}

	winPath := strings.ReplaceAll(candidate, "/", "\\")

	cmd := exec.Command("wslpath", "-u", winPath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("调用 wslpath 失败: %w (%s)", err, strings.TrimSpace(string(output)))
	}

	return strings.TrimSpace(string(output)), nil
}

func (a *App) resolveCLIBinaryPath() (string, error) {
	if a.cliBinaryPath != "" {
		return a.cliBinaryPath, nil
	}

	candidates := make([]string, 0, 8)

	if exePath, err := os.Executable(); err == nil {
		exeDir := filepath.Dir(exePath)
		candidates = append(candidates,
			filepath.Join(exeDir, "cos"),
			filepath.Join(exeDir, "cos-cli"),
		)

		parent := filepath.Dir(exeDir)
		candidates = append(candidates,
			filepath.Join(parent, "cos"),
			filepath.Join(parent, "bin", "cos"),
		)
	}

	if cwd, err := os.Getwd(); err == nil {
		candidates = append(candidates,
			filepath.Join(cwd, "cos"),
			filepath.Join(cwd, "bin", "cos"),
		)
	}

	if lookPath, err := exec.LookPath("cos"); err == nil {
		candidates = append(candidates, lookPath)
	}

	seen := make(map[string]struct{}, len(candidates))
	for _, candidate := range candidates {
		if candidate == "" {
			continue
		}
		if _, exists := seen[candidate]; exists {
			continue
		}
		seen[candidate] = struct{}{}

		info, err := os.Stat(candidate)
		if err != nil || info.IsDir() {
			continue
		}

		absPath, err := filepath.Abs(candidate)
		if err != nil {
			absPath = candidate
		}
		a.cliBinaryPath = absPath
		return a.cliBinaryPath, nil
	}

	return "", fmt.Errorf("未找到 CLI 可执行文件，请确认 cos 已构建或安装")
}
